In [ ]:
import pandas as pd
import plotly.express as px
In [ ]:
VESTING_PERIOD = 12*30
ACCUMULATION_DAYS = 2 * VESTING_PERIOD
DELAY_DAYS = VESTING_PERIOD
VESTED_TOKENS = 1000000
GOOD_LEAVER_FUTURE_KEEP = 0.5
BAD_LEAVER_CAN_KEEP = 0.1

def accumulated(day):
    return VESTED_TOKENS * day / ACCUMULATION_DAYS


def vested(day):
    effective_day = max(0, day - DELAY_DAYS)
    return VESTED_TOKENS * effective_day / (ACCUMULATION_DAYS - DELAY_DAYS)

vals = []
for day in range(0, ACCUMULATION_DAYS + 1):
    vals.append([
        accumulated(day),
        vested(day)
    ])

df = pd.DataFrame(data=vals, columns=["accumulated", "vested"])
fig = px.line(df, y=["accumulated", "vested"], title='no leaver event')
display(fig)
In [ ]:
def good_leaver_acc(day, leave_day):
    if day < leave_day:
        return accumulated(day)
    else:
        sofar = accumulated(leave_day)
        new_vested = (VESTED_TOKENS - sofar) * GOOD_LEAVER_FUTURE_KEEP
        return new_vested * (day - leave_day) / (ACCUMULATION_DAYS - leave_day) + sofar

def good_leaver_vested(day, leave_day):
    if day < DELAY_DAYS:
        return 0
    else:
        if day < leave_day:
            return vested(day)
        else:
            new_vested = good_leaver_acc(ACCUMULATION_DAYS, leave_day)
            sofar = vested(leave_day)
            cut_day = max(leave_day, DELAY_DAYS)
            return (new_vested - sofar) * (day - cut_day) / (ACCUMULATION_DAYS - cut_day) + sofar

def display_good_leaver(leaver_day, title):
    vals = []
    for day in range(0, ACCUMULATION_DAYS + 1):
        vals.append([
            accumulated(day),
            vested(day),
            good_leaver_acc(day, leaver_day),
            good_leaver_vested(day, leaver_day)
        ])

    df = pd.DataFrame(data=vals, columns=["accumulated", "vested" , "good leaver acc", "good leaver vest"])
    fig = px.line(df, y=["accumulated", "good leaver acc", "good leaver vest"], title=title)
    print(title)
    print(accumulated(leaver_day))
    print(good_leaver_acc(leaver_day, leaver_day))
    print(good_leaver_acc(ACCUMULATION_DAYS, leaver_day))
    print(good_leaver_vested(leaver_day, leaver_day))
    print(good_leaver_vested(ACCUMULATION_DAYS, leaver_day))
    display(fig)
    display(df)

display_good_leaver(180, "good leaver before cliff")
display_good_leaver(180 * 3, "good leaver after cliff")
display_good_leaver(450, "good leaver after cliff")
good leaver before cliff
250000.0
250000.0
625000.0
0
625000.0
accumulated vested good leaver acc good leaver vest
0 0.000000 0.000000 0.000000 0.000000
1 1388.888889 0.000000 1388.888889 0.000000
2 2777.777778 0.000000 2777.777778 0.000000
3 4166.666667 0.000000 4166.666667 0.000000
4 5555.555556 0.000000 5555.555556 0.000000
... ... ... ... ...
716 994444.444444 988888.888889 622222.222222 618055.555556
717 995833.333333 991666.666667 622916.666667 619791.666667
718 997222.222222 994444.444444 623611.111111 621527.777778
719 998611.111111 997222.222222 624305.555556 623263.888889
720 1000000.000000 1000000.000000 625000.000000 625000.000000

721 rows × 4 columns

good leaver after cliff
750000.0
750000.0
875000.0
500000.0
875000.0
accumulated vested good leaver acc good leaver vest
0 0.000000 0.000000 0.000000 0.000000
1 1388.888889 0.000000 1388.888889 0.000000
2 2777.777778 0.000000 2777.777778 0.000000
3 4166.666667 0.000000 4166.666667 0.000000
4 5555.555556 0.000000 5555.555556 0.000000
... ... ... ... ...
716 994444.444444 988888.888889 872222.222222 866666.666667
717 995833.333333 991666.666667 872916.666667 868750.000000
718 997222.222222 994444.444444 873611.111111 870833.333333
719 998611.111111 997222.222222 874305.555556 872916.666667
720 1000000.000000 1000000.000000 875000.000000 875000.000000

721 rows × 4 columns

good leaver after cliff
625000.0
625000.0
812500.0
250000.0
812500.0
accumulated vested good leaver acc good leaver vest
0 0.000000 0.000000 0.000000 0.000000
1 1388.888889 0.000000 1388.888889 0.000000
2 2777.777778 0.000000 2777.777778 0.000000
3 4166.666667 0.000000 4166.666667 0.000000
4 5555.555556 0.000000 5555.555556 0.000000
... ... ... ... ...
716 994444.444444 988888.888889 809722.222222 804166.666667
717 995833.333333 991666.666667 810416.666667 806250.000000
718 997222.222222 994444.444444 811111.111111 808333.333333
719 998611.111111 997222.222222 811805.555556 810416.666667
720 1000000.000000 1000000.000000 812500.000000 812500.000000

721 rows × 4 columns

In [ ]:
def bad_leaver_acc(day, leave_day):
    if day < leave_day:
        return accumulated(day)
    else:
        if leave_day < DELAY_DAYS:
            return accumulated(leave_day) * BAD_LEAVER_CAN_KEEP
        else:
            return vested(leave_day)

def bad_leaver_vested(day, leave_day):
    if day < DELAY_DAYS:
        return 0
    else:
        if day < leave_day:
            return vested(day)
        else:
            new_vested = bad_leaver_acc(ACCUMULATION_DAYS, leave_day)
            sofar = vested(leave_day)
            cut_day = max(leave_day, DELAY_DAYS)
            return (new_vested - sofar) * (day - cut_day) / (ACCUMULATION_DAYS - cut_day) + sofar

def display_bad_leaver(leaver_day, title):
    vals = []
    for day in range(0, ACCUMULATION_DAYS + 1):
        vals.append([
            accumulated(day),
            vested(day),
            bad_leaver_acc(day, leaver_day),
            bad_leaver_vested(day, leaver_day)
        ])

    df = pd.DataFrame(data=vals, columns=["accumulated", "vested" , "bad leaver acc", "bad leaver vested"])
    fig = px.line(df, y=["accumulated" ,"bad leaver acc", "bad leaver vested"], title=title)
    print(title)
    print(accumulated(leaver_day))
    print(bad_leaver_acc(leaver_day, leaver_day))
    print(bad_leaver_acc(ACCUMULATION_DAYS, leaver_day))
    print(bad_leaver_vested(leaver_day, leaver_day))
    print(bad_leaver_vested(ACCUMULATION_DAYS, leaver_day))
    display(fig)
    display(df)

display_bad_leaver(180, "bad leaver before cliff")
display_bad_leaver(180 * 3, "bad leaver after cliff")
display_bad_leaver(450, "bad leaver after cliff")
bad leaver before cliff
250000.0
25000.0
25000.0
0
25000.0
accumulated vested bad leaver acc bad leaver vested
0 0.000000 0.000000 0.000000 0.000000
1 1388.888889 0.000000 1388.888889 0.000000
2 2777.777778 0.000000 2777.777778 0.000000
3 4166.666667 0.000000 4166.666667 0.000000
4 5555.555556 0.000000 5555.555556 0.000000
... ... ... ... ...
716 994444.444444 988888.888889 25000.000000 24722.222222
717 995833.333333 991666.666667 25000.000000 24791.666667
718 997222.222222 994444.444444 25000.000000 24861.111111
719 998611.111111 997222.222222 25000.000000 24930.555556
720 1000000.000000 1000000.000000 25000.000000 25000.000000

721 rows × 4 columns

bad leaver after cliff
750000.0
500000.0
500000.0
500000.0
500000.0
accumulated vested bad leaver acc bad leaver vested
0 0.000000 0.000000 0.000000 0.0
1 1388.888889 0.000000 1388.888889 0.0
2 2777.777778 0.000000 2777.777778 0.0
3 4166.666667 0.000000 4166.666667 0.0
4 5555.555556 0.000000 5555.555556 0.0
... ... ... ... ...
716 994444.444444 988888.888889 500000.000000 500000.0
717 995833.333333 991666.666667 500000.000000 500000.0
718 997222.222222 994444.444444 500000.000000 500000.0
719 998611.111111 997222.222222 500000.000000 500000.0
720 1000000.000000 1000000.000000 500000.000000 500000.0

721 rows × 4 columns

bad leaver after cliff
625000.0
250000.0
250000.0
250000.0
250000.0
accumulated vested bad leaver acc bad leaver vested
0 0.000000 0.000000 0.000000 0.0
1 1388.888889 0.000000 1388.888889 0.0
2 2777.777778 0.000000 2777.777778 0.0
3 4166.666667 0.000000 4166.666667 0.0
4 5555.555556 0.000000 5555.555556 0.0
... ... ... ... ...
716 994444.444444 988888.888889 250000.000000 250000.0
717 995833.333333 991666.666667 250000.000000 250000.0
718 997222.222222 994444.444444 250000.000000 250000.0
719 998611.111111 997222.222222 250000.000000 250000.0
720 1000000.000000 1000000.000000 250000.000000 250000.0

721 rows × 4 columns